﻿using CSRedis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace Sprout.Cache.Redis
{
    public static partial class RedisService
    {
        static Dictionary<string, CSRedisClient> redisClientDic;
        static Dictionary<string, RedisKeyExpiry> redisKeyExpiryDic;
        #region 初始化
        /// <summary>
        /// 初始化redis服务
        /// </summary>
        /// <param name="redisConnectionOptions">DB配置信息</param>
        /// <param name="redisKeyOptions">key配置信息</param>
        public static void Initialize(IEnumerable<RedisConnectionOption> redisConnectionOptions, IEnumerable<RedisKeyOption> redisKeyOptions)
        {
            Initialize(redisConnectionOptions);

            Initialize(redisKeyOptions);
        }

        /// <summary>
        /// 初始化redis服务
        /// </summary>
        /// <param name="redisConnectionOptions">DB配置信息</param>
        /// <param name="redisKeyExpirys">key过期配置信息</param>
        public static void Initialize(IEnumerable<RedisConnectionOption> redisConnectionOptions, IEnumerable<RedisKeyExpiry> redisKeyExpirys)
        {
            Initialize(redisConnectionOptions);

            Initialize(redisKeyExpirys);
        }

        /// <summary>
        /// 初始化redis连接
        /// </summary>
        /// <param name="redisConnectionOptions">DB配置信息</param>
        public static void Initialize(IEnumerable<RedisConnectionOption> redisConnectionOptions)
        {
            if (redisConnectionOptions == null || redisConnectionOptions.Any() == false)
            {
                throw new Exception("初始化redis错误，RedisConnection为空");
            }

            redisClientDic = new Dictionary<string, CSRedisClient>();
            foreach (var item in redisConnectionOptions)
            {
                if (redisClientDic.ContainsKey(item.ConnectionName))
                {
                    throw new Exception($"初始化redis错误，RedisConnection配置中,ConnectionName: {item.ConnectionName}重复");
                }
                CSRedisClient redisClient = new CSRedisClient(item.ConnectionString);
                redisClientDic.Add(item.ConnectionName, redisClient);
            }
        }
        /// <summary>
        /// 初始化redis Key
        /// </summary>
        /// <param name="redisKeyOptions">key配置信息</param>
        public static void Initialize(IEnumerable<RedisKeyOption> redisKeyOptions)
        {
            redisKeyExpiryDic = new Dictionary<string, RedisKeyExpiry>();
            foreach (var option in redisKeyOptions)
            {
                foreach (var item in option.RedisKeyExpirys)
                {
                    if (redisKeyExpiryDic.ContainsKey(item.Key))
                    {
                        throw new Exception($"初始化redis key 错误，key: {item.Key} 重复");
                    }
                    redisKeyExpiryDic.Add(item.Key, new RedisKeyExpiry
                    {
                        ConnectionName = option.ConnectionName,
                        Key = item.Key,
                        ExpiryType = item.ExpiryType,
                        Interval = item.Interval
                    });
                }
            }
        }
        /// <summary>
        /// 初始化redis key
        /// </summary>
        /// <param name="redisKeyExpirys">key过期配置信息</param>
        public static void Initialize(IEnumerable<RedisKeyExpiry> redisKeyExpirys)
        {
            redisKeyExpiryDic = new Dictionary<string, RedisKeyExpiry>();
            foreach (var item in redisKeyExpirys)
            {
                if (redisKeyExpiryDic.ContainsKey(item.Key))
                {
                    throw new Exception($"初始化redis key 错误，key: {item.Key} 重复");
                }
                redisKeyExpiryDic.Add(item.Key, new RedisKeyExpiry
                {
                    ConnectionName = item.ConnectionName,
                    Key = item.Key,
                    ExpiryType = item.ExpiryType,
                    Interval = item.Interval
                });
            }
        }
        #endregion

        #region 获取CSRedisClient
        /// <summary>
        /// 获取CSRedisClient
        /// </summary>
        /// <param name="connectionName">连接名称</param>
        /// <returns></returns>
        public static CSRedisClient GetRedisClientByConnectionName(string connectionName)
        {
            if (redisClientDic.ContainsKey(connectionName) == false)
            {
                throw new Exception($"redis缓存连接 ConnectionName: {connectionName}不存在 ");
            }
            return redisClientDic[connectionName];
        }

        /// <summary>
        /// 获取第一个CSRedisClient
        /// </summary>
        /// <returns></returns>
        public static CSRedisClient GetRedisClientFirst()
        {
            return redisClientDic.First().Value;
        }
        /// <summary>
        /// 获取 redisClient
        /// 多个key必须在同一个db中
        /// </summary>
        /// <param name="keys"></param>
        /// <returns></returns>
        public static CSRedisClient GetRedisClient(string[] keys)
        {
            if (keys == null || keys.Length == 0)
            {
                throw new Exception("keys必须为有值的集合");
            }
            return GetRedisClient(keys[0]);
        }

        /// <summary>
        /// 获取 redisClient
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <returns></returns>
        public static CSRedisClient GetRedisClient(string key)
        {
            if (redisKeyExpiryDic.ContainsKey(key) == false)
            {
                if (key.IndexOf(":") > -1)
                {
                    string likeKey = key.Substring(0, key.LastIndexOf(":") + 1);
                    if (redisKeyExpiryDic.ContainsKey(likeKey) == false)
                    {
                        throw new Exception($"redis缓存key: {key}不存在，且{likeKey}不存在 ");
                    }
                    else
                    {
                        var redisKeyExpiry = redisKeyExpiryDic[likeKey];
                        return GetRedisClientByConnectionName(redisKeyExpiry.ConnectionName);
                    }
                }
                else
                {
                    throw new Exception($"redis缓存key: {key}不存在");
                }
            }
            else
            {
                var redisKeyExpiry = redisKeyExpiryDic[key];
                return GetRedisClientByConnectionName(redisKeyExpiry.ConnectionName);
            }
        }

        #endregion

        #region 

        /// <summary>
        /// 获取key配置的过期时间
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static TimeSpan? GetExpire(string key)
        {
            TimeSpan? expiry = null;
            if (redisKeyExpiryDic != null)
            {
                if (redisKeyExpiryDic.ContainsKey(key) == false)
                {
                    key = key.Substring(0, key.LastIndexOf(":") + 1);
                    if (redisKeyExpiryDic.ContainsKey(key) == false)
                    {
                        return expiry;
                    }
                }
                var redisKeyExpiry = redisKeyExpiryDic[key];
                if (string.IsNullOrEmpty(redisKeyExpiry.ExpiryType))
                {
                    expiry = null;
                    return expiry;
                }
                else
                {
                    switch (redisKeyExpiry.ExpiryType.ToLower())
                    {
                        case "second":
                            return TimeSpan.FromSeconds(redisKeyExpiry.Interval);
                        case "minute":
                            return TimeSpan.FromMinutes(redisKeyExpiry.Interval);
                        case "hour":
                            return TimeSpan.FromHours(redisKeyExpiry.Interval);
                        case "day":
                            return TimeSpan.FromDays(redisKeyExpiry.Interval);
                        case "month":
                            return (DateTime.Now.AddMonths(redisKeyExpiry.Interval) - DateTime.Now);
                        case "year":
                            return (DateTime.Now.AddYears(redisKeyExpiry.Interval) - DateTime.Now);
                        default:
                            throw new Exception("不支持的过期时间类型");
                    }
                }
            }

            return expiry;
        }

        /// <summary>
        /// 设置过期时间
        /// </summary>
        /// <param name="redisClient">redis客户端</param>
        /// <param name="key">key</param>
        /// <returns></returns>
        public static bool Expire(CSRedisClient redisClient, string key)
        {
            TimeSpan? expire = GetExpire(key);

            if (expire.HasValue)
            {
                return redisClient.Expire(key, expire.Value);
            }
            else
            {
                return redisClient.Persist(key);
            }
        }

        /// <summary>
        /// 设置过期时间
        /// </summary>
        /// <param name="redisClient">redis客户端</param>
        /// <param name="key">key</param>
        /// <param name="expire">过期时间</param>
        /// <returns></returns>
        public static bool Expire(CSRedisClient redisClient, string key, TimeSpan expire)
        {
            return redisClient.Expire(key, expire);
        }

        #endregion

        #region key
        /// <summary>
        /// 删除缓存
        /// 如果多个key必须在同一个db中
        /// </summary>
        /// <param name="keys">不含prefix前辍</param>
        /// <returns>是否成功</returns>
        public static long Del(params string[] keys)
        {
            if (keys == null || keys.Length == 0)
            {
                return 0;
            }
            var redisClient = GetRedisClient(keys);
            var count = redisClient.Del(keys);
            return count;
        }

        /// <summary>
        /// 检查给定 key 是否存在
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns>是否成功</returns>
        public static bool Exists(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.Exists(key);
        }
        /// <summary>
        /// 为给定 key 设置过期时间
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="seconds">过期秒数</param>
        /// <returns>是否成功</returns>
        public static bool Expire(string key, int seconds)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.Expire(key, seconds);
        }
        /// <summary>
        /// 为给定 key 设置过期时间
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="expire">过期时间</param>
        /// <returns>是否成功</returns>
        public static bool Expire(string key, TimeSpan expire)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.Expire(key, expire);
        }

        /// <summary>
        /// 为给定 key 设置过期时间
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns>是否成功</returns>
        public static bool Expire(string key)
        {
            var redisClient = GetRedisClient(key);
            TimeSpan? expire = GetExpire(key);
            if (expire.HasValue)
            {
                return redisClient.Expire(key, expire.Value);
            }
            else
            {
                return redisClient.Persist(key);
            }
        }
        /// <summary>
        /// 为给定 key 设置过期时间，指定时间过期
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="expire">指定时间</param>
        /// <returns>是否成功</returns>
        public static bool ExpireAt(string key, DateTime expire)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ExpireAt(key, expire);
        }
        /// <summary>
        /// 该返回给定 key 锁储存的值所使用的内部表示(representation)
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static string ObjectEncoding(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ObjectEncoding(key);
        }

        /// <summary>
        /// 该返回给定 key 引用所储存的值的次数。此命令主要用于除错
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static long? ObjectRefCount(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ObjectRefCount(key);
        }

        /// <summary>
        /// 返回给定 key 自储存以来的空转时间(idle， 没有被读取也没有被写入)，以秒为单位
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static long? ObjectIdleTime(string key)
        {
            var redisClient = GetRedisClient(key);

            return redisClient.ObjectIdleTime(key);
        }

        /// <summary>
        /// 移除 key 的过期时间，key 将持久保持
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static bool Persist(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.Persist(key);
        }

        /// <summary>
        /// 以秒为单位，返回给定 key 的剩余生存时间
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static long Ttl(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.Ttl(key);
        }

        /// <summary>
        /// 以毫秒为单位返回 key 的剩余的过期时间
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static long PTtl(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.PTtl(key);
        }

        /// <summary>
        /// 修改 key 的名称,newKey存在时覆盖
        /// </summary>
        /// <param name="key">旧名称</param>
        /// <param name="newKey">新名称</param>
        /// <returns></returns>
        public static bool Rename(string key, string newKey)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.Rename(key, newKey);
        }

        /// <summary>
        /// 修改 key 的名称，newKey存在时，返回失败
        /// </summary>
        /// <param name="key">旧名称，不含prefix前辍</param>
        /// <param name="newKey">新名称，不含prefix前辍</param>
        /// <returns></returns>
        public static bool RenameNx(string key, string newKey)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.RenameNx(key, newKey);
        }

        /// <summary>
        /// 查询keys，会加上前缀
        /// </summary>
        /// <param name="pattern">匹配</param>
        /// <returns>key数组</returns>
        public static string[] Keys(string pattern)
        {
            var redisClient = GetRedisClient(pattern);
            string prefix = GetPrefix(redisClient);
            pattern = string.Concat(prefix, pattern);
            var keys = redisClient.Keys(pattern);
            return RemovePrefix(prefix, keys);
        }

        #endregion

        #region String

        /// <summary>
        /// 如果 key 已经存在并且是一个字符串， APPEND 命令将指定的 value 追加到该 key 原来值（value）的末尾
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="value">字符串</param>
        /// <returns>追加指定值之后， key 中字符串的长度</returns>
        public static long Append(string key, string value)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.Append(key, value);
        }

        /// <summary>
        /// 获取指定 key 的值
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static string Get(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.Get(key);
        }

        /// <summary>
        /// 获取指定 key 的值
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static T Get<T>(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.Get<T>(key);
        }

        /// <summary>
        /// 返回 key 中字符串值的子字符
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="start">开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="end">结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <returns></returns>
        public static string GetRange(string key, long start, long end)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.GetRange(key, start, end);
        }

        /// <summary>
        /// 将给定 key 的值设为 value ，并返回 key 的旧值(old value)
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static string GetSet(string key, object value)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.GetSet(key, value);
        }

        /// <summary>
        /// 将给定 key 的值设为 value ，并返回 key 的旧值(old value)
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static T GetSet<T>(string key, object value)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.GetSet<T>(key, value);
        }

        /// <summary>
        /// 获取多个指定 key 的值(数组)，必须在同一个db中
        /// </summary>
        /// <param name="keys">不含prefix前辍</param>
        /// <returns></returns>
        public static string[] MGet(params string[] keys)
        {
            var redisClient = GetRedisClient(keys);
            return redisClient.MGet(keys);
        }

        /// <summary>
        /// 获取多个指定 key 的值(数组)，必须在同一个db中
        /// </summary>
        /// <param name="keys">不含prefix前辍</param>
        /// <returns></returns>
        public static T[] MGet<T>(params string[] keys)
        {
            var redisClient = GetRedisClient(keys);
            return redisClient.MGet<T>(keys);
        }
        /// <summary>
        /// 设置指定 key 的值，所有写入参数object都支持string | byte[] | 数值 | 对象
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="value">值</param>
        /// <param name="expireSeconds">过期(秒单位)</param>
        /// <param name="exists">Nx, Xx</param>
        /// <returns></returns>
        public static bool Set(string key, object value, int expireSeconds = -1, RedisExistence? exists = null)
        {
            var redisClient = GetRedisClient(key);
            var success = redisClient.Set(key, value, expireSeconds, exists);
            return success;
        }
        /// <summary>
        /// 设置指定 key 的值，所有写入参数object都支持string | byte[] | 数值 | 对象
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="value">值</param>
        /// <param name="expire">过期时间</param>
        /// <param name="exists">Nx, Xx</param>
        /// <returns></returns>
        public static bool Set(string key, object value, TimeSpan expire, RedisExistence? exists = null)
        {
            var redisClient = GetRedisClient(key);
            int expireSeconds = (int)expire.TotalSeconds;
            var success = redisClient.Set(key, value, expireSeconds, exists);
            return success;
        }

        /// <summary>
        /// 返回 key 所储存的字符串值的长度
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static long StrLen(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.StrLen(key);
        }
        /// <summary>
        /// 只有在 key 不存在时设置 key 的值
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool SetNx(string key, object value)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.SetNx(key, value);
        }

        #endregion

        #region Hash

        /// <summary>
        /// 删除一个或多个哈希表字段
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="fields">字段</param>
        /// <returns></returns>
        public static long HDel(string key, params string[] fields)
        {
            var redisClient = GetRedisClient(key);

            return redisClient.HDel(key, fields);
        }

        /// <summary>
        /// 查看哈希表 key 中，指定的字段是否存在
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="field">字段</param>
        /// <returns></returns>
        public static bool HExists(string key, string field)
        {
            var redisClient = GetRedisClient(key);

            return redisClient.HExists(key, field);
        }

        /// <summary>
        /// 获取存储在哈希表中指定字段的值
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="field">字段</param>
        /// <returns></returns>
        public static string HGet(string key, string field)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.HGet(key, field);
        }
        /// <summary>
        /// 获取存储在哈希表中指定字段的值
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="field">字段</param>
        /// <returns></returns>
        public static T HGet<T>(string key, string field)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.HGet<T>(key, field);
        }

        /// <summary>
        /// 获取在哈希表中指定 key 的所有字段和值
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static Dictionary<string, string> HGetAll(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.HGetAll(key);
        }

        /// <summary>
        /// 获取在哈希表中指定 key 的所有字段和值
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static Dictionary<string, T> HGetAll<T>(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.HGetAll<T>(key);
        }

        /// <summary>
        /// 获取所有哈希表中的字段
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static string[] HKeys(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.HKeys(key);
        }
        /// <summary>
        /// 获取哈希表中字段的数量
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static long HLen(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.HLen(key);
        }

        /// <summary>
        /// 获取存储在哈希表中多个字段的值
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="fields">字段</param>
        /// <returns></returns>
        public static string[] HMGet(string key, params string[] fields)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.HMGet(key);
        }

        /// <summary>
        /// 获取存储在哈希表中多个字段的值
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="fields">一个或多个字段</param>
        /// <returns></returns>
        public static T[] HMGet<T>(string key, params string[] fields)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.HMGet<T>(key);
        }
        /// <summary>
        /// 同时将多个 field-value (域-值)对设置到哈希表 key 中
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="keyValues">key1 value1 [key2 value2]</param>
        /// <returns></returns>
        public static bool HMSet(string key, params object[] keyValues)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.HMSet(key, keyValues);
        }

        /// <summary>
        /// 同时将多个 field-value (域-值)对设置到哈希表 key 中
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="fieldValues">一个或多个 field value 值</param>
        /// <returns></returns>
        public static bool HMSet(string key, params HashAddDto[] fieldValues)
        {
            List<object> list = new List<object>();
            foreach (var item in fieldValues)
            {
                list.Add(item.Field);
                list.Add(item.Value);
            }
            var redisClient = GetRedisClient(key);
            return redisClient.HMSet(key, list.ToArray());
        }

        /// <summary>
        /// 将哈希表 key 中的字段 field 的值设为 value
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="field">字段</param>
        /// <param name="value">值</param>
        /// <returns>如果字段是哈希表中的一个新建字段，并且值设置成功，返回true。如果哈希表中域字段已经存在且旧值已被新值覆盖，返回false。</returns>
        public static bool HSet(string key, string field, object value)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.HSet(key, field, value);
        }
        /// <summary>
        /// 迭代哈希表中的键值对
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="cursor">位置</param>
        /// <param name="pattern">模式</param>
        /// <param name="count">数量</param>
        /// <returns></returns>
        public static RedisScan<(string field, string value)> HScan(string key, int cursor, string pattern = null, int? count = null)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.HScan(key, cursor, pattern, count);
        }

        /// <summary>
        /// 迭代哈希表中的键值对
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="cursor">位置</param>
        /// <param name="pattern">模式</param>
        /// <param name="count">数量</param>
        /// <returns></returns>
        public static RedisScan<(string field, T value)> HScan<T>(string key, int cursor, string pattern = null, int? count = null)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.HScan<T>(key, cursor, pattern, count);
        }

        #endregion

        #region List

        /// <summary>
        /// 获取列表指定范围内的元素
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="start">开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop">结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <returns></returns>
        public static string[] LRange(string key, long start, long stop)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.LRange(key, start, stop);
        }

        /// <summary>
        /// 获取列表指定范围内的元素
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="start">开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop">结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <returns></returns>
        public static T[] LRange<T>(string key, long start, long stop)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.LRange<T>(key, start, stop);
        }

        /// <summary>
        /// 获取列表长度
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static long LLen(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.LLen(key);
        }

        /// <summary>
        /// 通过索引获取列表中的元素
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="index">索引</param>
        /// <returns></returns>
        public static string LIndex(string key, long index)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.LIndex(key, index);
        }

        /// <summary>
        /// 通过索引获取列表中的元素
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="index">索引</param>
        /// <returns></returns>
        public static T LIndex<T>(string key, long index)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.LIndex<T>(key, index);
        }
        /// <summary>
        /// 根据参数 count 的值，移除列表中与参数 value 相等的元素
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="count">移除的数量，大于0时从表头删除数量count，小于0时从表尾删除数量-count，等于0移除所有</param>
        /// <param name="value">元素</param>
        /// <returns></returns>
        public static long LRem(string key, long count, object value)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.LRem(key, count, value);
        }
        /// <summary>
        /// 通过索引设置列表元素的值
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="index">索引</param>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static bool LSet(string key, long index, object value)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.LSet(key, index, value);
        }

        /// <summary>
        /// 对一个列表进行修剪，让列表只保留指定区间内的元素，不在指定区间之内的元素都将被删除
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="start">开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop">结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <returns></returns>
        public static bool LTrim(string key, long start, long stop)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.LTrim(key, start, stop);
        }

        /// <summary>
        /// 移出并获取列表的第一个元素
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static string LPop(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.LPop(key);
        }
        /// <summary>
        /// 移出并获取列表的第一个元素
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static T LPop<T>(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.LPop<T>(key);
        }
        /// <summary>
        /// 移除并获取列表最后一个元素
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static string RPop(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.RPop(key);
        }

        /// <summary>
        /// 移除并获取列表最后一个元素
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static T RPop<T>(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.RPop<T>(key);
        }

        /// <summary>
        /// 在列表中添加一个或多个值
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="value">一个或多个值</param>
        /// <returns>执行 RPUSH 命令后，列表的长度</returns>
        public static long RPush<T>(string key, params T[] value)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.RPush(key, value);
        }
        /// <summary>
        /// 为已存在的列表添加值
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="value">一个或多个值</param>
        /// <returns>执行 RPUSHX 命令后，列表的长度</returns>
        public static long RPushX(string key, object value)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.RPushX(key, value);
        }
        /// <summary>
        /// 将一个或多个值插入到列表头部
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="value">一个或多个值</param>
        /// <returns>执行 LPUSH 命令后，列表的长度</returns>
        public static long LPush<T>(string key, params T[] value)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.LPush(key, value);
        }
        /// <summary>
        /// 将一个值插入到已存在的列表头部
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="value">值</param>
        /// <returns>执行 LPUSHX 命令后，列表的长度。</returns>
        public static long LPushX(string key, object value)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.LPushX(key, value);
        }
        #endregion

        #region Set

        /// <summary>
        /// 向集合添加一个或多个成员
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="members">一个或多个成员</param>
        /// <returns></returns>
        public static long SAdd<T>(string key, params T[] members)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.SAdd(key, members);
        }

        /// <summary>
        /// 获取集合的成员数
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static long SCard(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.SCard(key);
        }

        /// <summary>
        /// 返回给定所有集合的差集
        /// </summary>
        /// <param name="keys">不含prefix前辍</param>
        /// <returns></returns>
        public static string[] SDiff(params string[] keys)
        {
            var redisClient = GetRedisClient(keys);
            return redisClient.SDiff(keys);
        }

        /// <summary>
        /// 返回给定所有集合的差集
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="keys">不含prefix前辍</param>
        /// <returns></returns>
        public static T[] SDiff<T>(params string[] keys)
        {
            var redisClient = GetRedisClient(keys);
            return redisClient.SDiff<T>(keys);
        }
        /// <summary>
        /// 返回给定所有集合的交集
        /// </summary>
        /// <param name="keys">不含prefix前辍</param>
        /// <returns></returns>
        public static string[] SInter(params string[] keys)
        {
            var redisClient = GetRedisClient(keys);
            return redisClient.SInter(keys);
        }
        /// <summary>
        /// 返回给定所有集合的交集
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="keys">不含prefix前辍</param>
        /// <returns></returns>
        public static T[] SInter<T>(params string[] keys)
        {
            var redisClient = GetRedisClient(keys);
            return redisClient.SInter<T>(keys);
        }

        /// <summary>
        /// 判断 member 元素是否是集合 key 的成员
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="member">成员</param>
        /// <returns></returns>
        public static bool SIsMember(string key, object member)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.SIsMember(key, member);
        }

        /// <summary>
        /// 返回集合中的所有成员
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static string[] SMembers(string key)
        {
            var redisClient = GetRedisClient(key);

            return redisClient.SMembers(key);
        }

        /// <summary>
        /// 返回集合中的所有成员
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static T[] SMembers<T>(string key)
        {
            var redisClient = GetRedisClient(key);

            return redisClient.SMembers<T>(key);
        }

        /// <summary>
        /// 移除并返回集合中的一个随机元素
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static string SPop(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.SPop(key);
        }

        /// <summary>
        /// 移除并返回集合中的一个随机元素
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static T SPop<T>(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.SPop<T>(key);
        }

        /// <summary>
        /// 返回集合中的一个随机元素
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static string SRandMember(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.SRandMember(key);
        }

        /// <summary>
        /// 返回集合中的一个随机元素
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static T SRandMember<T>(string key)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.SRandMember<T>(key);
        }

        /// <summary>
        /// 返回集合中一个或多个随机数的元素
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="count">返回个数</param>
        /// <returns></returns>
        public static string[] SRandMembers(string key, int count = 1)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.SRandMembers(key);
        }

        /// <summary>
        /// 返回集合中一个或多个随机数的元素
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="count">返回个数</param>
        /// <returns></returns>
        public static T[] SRandMembers<T>(string key, int count = 1)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.SRandMembers<T>(key);
        }

        /// <summary>
        /// 移除集合中一个或多个成员
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="members">一个或多个成员</param>
        /// <returns></returns>
        public static long SRem<T>(string key, params T[] members)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.SRem(key, members);
        }

        /// <summary>
        /// 返回所有给定集合的并集
        /// </summary>
        /// <param name="keys">不含prefix前辍</param>
        /// <returns></returns>
        public static string[] SUnion(params string[] keys)
        {
            var redisClient = GetRedisClient(keys);
            return redisClient.SUnion(keys);
        }

        /// <summary>
        /// 返回所有给定集合的并集
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="keys">不含prefix前辍</param>
        /// <returns></returns>
        public static T[] SUnion<T>(params string[] keys)
        {
            var redisClient = GetRedisClient(keys);
            return redisClient.SUnion<T>(keys);
        }

        /// <summary>
        /// 迭代集合中的元素
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="cursor">位置</param>
        /// <param name="pattern">模式</param>
        /// <param name="count">数量</param>
        /// <returns></returns>
        public static RedisScan<string> SScan(string key, int cursor, string pattern = null, int? count = null)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.SScan(key, cursor, pattern, count);
        }

        /// <summary>
        /// 迭代集合中的元素
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="cursor">位置</param>
        /// <param name="pattern">模式</param>
        /// <param name="count">数量</param>
        /// <returns></returns>
        public static RedisScan<T> SScan<T>(string key, int cursor, string pattern = null, int? count = null)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.SScan<T>(key, cursor, pattern, count);
        }

        #endregion

        #region Sorted Set

        /// <summary>
        /// 向有序集合添加一个或多个成员，或者更新已存在成员的分数
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="scoreMembers">一个或多个成员分数</param>
        /// <returns></returns>
        public static long ZAdd(string key, params (decimal score, object member)[] scoreMembers)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZAdd(key, scoreMembers);
        }

        /// <summary>
        /// 向有序集合添加一个或多个成员，或者更新已存在成员的分数
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="scoreMembers">一个或多个成员分数</param>
        /// <returns></returns>
        public static long ZAdd(string key, params SortedSetAddDto[] scoreMembers)
        {
            List<(decimal, object)> list = new List<(decimal, object)>();
            foreach (var item in scoreMembers)
            {
                list.Add((item.Score, item.Member));
            }
            var redisClient = GetRedisClient(key);
            return redisClient.ZAdd(key, list.ToArray());
        }

        /// <summary>
        /// 获取有序集合的成员数量
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <returns></returns>
        public static long ZCard(string key)
        {
            var redisClient = GetRedisClient(key);

            return redisClient.ZCard(key);
        }

        /// <summary>
        /// 计算在有序集合中指定区间分数的成员数量
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="min">分数最小值 decimal.MinValue</param>
        /// <param name="max">分数最大值 decimal.MaxValue</param>
        /// <returns></returns>
        public static long ZCount(string key, decimal min, decimal max)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZCount(key, min, max);
        }

        /// <summary>
        /// 计算在有序集合中指定区间分数的成员数量
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="min">分数最小值 -inf (1 1</param>
        /// <param name="max">分数最大值 +inf (10 10</param>
        /// <returns></returns>
        public static long ZCount(string key, string min, string max)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZCount(key, min, max);
        }

        /// <summary>
        /// 有序集合中对指定成员的分数加上增量 increment
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="member">成员</param>
        /// <param name="increment">增量值(默认=1)</param>
        /// <returns></returns>
        public static decimal ZIncrBy(string key, string member, decimal increment = 1)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZIncrBy(key, member, increment);
        }

        /// <summary>
        /// 通过索引区间返回有序集合成指定区间内的成员
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="start">开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop">结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <returns></returns>
        public static string[] ZRange(string key, long start, long stop)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRange(key, start, stop);
        }

        /// <summary>
        /// 通过索引区间返回有序集合成指定区间内的成员
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="start">开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop">结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <returns></returns>
        public static T[] ZRange<T>(string key, long start, long stop)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRange<T>(key, start, stop);
        }

        /// <summary>
        /// 通过索引区间返回有序集合成指定区间内的成员和分数
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="start">开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop">结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <returns></returns>
        public static (string member, decimal score)[] ZRangeWithScores(string key, long start, long stop)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRangeWithScores(key, start, stop);
        }

        /// <summary>
        /// 通过索引区间返回有序集合成指定区间内的成员和分数
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="start">开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop">结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <returns></returns>
        public static (T member, decimal score)[] ZRangeWithScores<T>(string key, long start, long stop)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRangeWithScores<T>(key, start, stop);
        }

        /// <summary>
        /// 通过分数返回有序集合指定区间内的成员
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="min">分数最小值 decimal.MinValue</param>
        /// <param name="max">分数最大值 decimal.MaxValue</param>
        /// <param name="limit">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public static string[] ZRangeByScore(string key, decimal min, decimal max, long? limit = null, long offset = 0)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRangeByScore(key, min, max, limit, offset);
        }

        /// <summary>
        /// 通过分数返回有序集合指定区间内的成员
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="min">分数最小值 decimal.MinValue</param>
        /// <param name="max">分数最大值 decimal.MaxValue</param>
        /// <param name="limit">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public static T[] ZRangeByScore<T>(string key, decimal min, decimal max, long? limit = null, long offset = 0)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRangeByScore<T>(key, min, max, limit, offset);
        }

        /// <summary>
        /// 通过分数返回有序集合指定区间内的成员
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="min">分数最小值 -inf (1 1</param>
        /// <param name="max">分数最大值 +inf (10 10</param>
        /// <param name="limit">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public static string[] ZRangeByScore(string key, string min, string max, long? limit = null, long offset = 0)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRangeByScore(key, min, max, limit, offset);
        }

        /// <summary>
        /// 通过分数返回有序集合指定区间内的成员
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="min">分数最小值 -inf (1 1</param>
        /// <param name="max">分数最大值 +inf (10 10</param>
        /// <param name="limit">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public static T[] ZRangeByScore<T>(string key, string min, string max, long? limit = null, long offset = 0)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRangeByScore<T>(key, min, max, limit, offset);
        }

        /// <summary>
        /// 通过分数返回有序集合指定区间内的成员和分数
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="min">分数最小值 decimal.MinValue</param>
        /// <param name="max">分数最大值 decimal.MaxValue</param>
        /// <param name="limit">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public static (string member, decimal score)[] ZRangeByScoreWithScores(string key, decimal min, decimal max, long? limit = null, long offset = 0)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRangeByScoreWithScores(key, min, max, limit, offset);
        }

        /// <summary>
        /// 通过分数返回有序集合指定区间内的成员和分数
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="min">分数最小值 decimal.MinValue</param>
        /// <param name="max">分数最大值 decimal.MaxValue</param>
        /// <param name="limit">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public static (T member, decimal score)[] ZRangeByScoreWithScores<T>(string key, decimal min, decimal max, long? limit = null, long offset = 0)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRangeByScoreWithScores<T>(key, min, max, limit, offset);
        }

        /// <summary>
        /// 通过分数返回有序集合指定区间内的成员和分数
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="min">分数最小值 -inf (1 1</param>
        /// <param name="max">分数最大值 +inf (10 10</param>
        /// <param name="limit">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public static (string member, decimal score)[] ZRangeByScoreWithScores(string key, string min, string max, long? limit = null, long offset = 0)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRangeByScoreWithScores(key, min, max, limit, offset);
        }

        /// <summary>
        /// 通过分数返回有序集合指定区间内的成员和分数
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="min">分数最小值 -inf (1 1</param>
        /// <param name="max">分数最大值 +inf (10 10</param>
        /// <param name="limit">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public static (T member, decimal score)[] ZRangeByScoreWithScores<T>(string key, string min, string max, long? limit = null, long offset = 0)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRangeByScoreWithScores<T>(key, min, max, limit, offset);
        }

        /// <summary>
        /// 返回有序集合中指定成员的索引
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="member">成员</param>
        /// <returns></returns>
        public static long? ZRank(string key, object member)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRank(key, member);
        }

        /// <summary>
        /// 移除有序集合中的一个或多个成员
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="member">一个或多个成员</param>
        /// <returns></returns>
        public static long ZRem<T>(string key, params T[] member)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRem(key, member);
        }

        /// <summary>
        /// 移除有序集合中给定的排名区间的所有成员
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="start">开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop">结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <returns></returns>
        public static long ZRemRangeByRank(string key, long start, long stop)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRemRangeByRank(key, start, stop);
        }

        /// <summary>
        /// 移除有序集合中给定的分数区间的所有成员
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="min">分数最小值 decimal.MinValue</param>
        /// <param name="max">分数最大值 decimal.MaxValue</param>
        /// <returns></returns>
        public static long ZRemRangeByScore(string key, decimal min, decimal max)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRemRangeByScore(key, min, max);
        }

        /// <summary>
        /// 移除有序集合中给定的分数区间的所有成员
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="min">分数最小值 -inf (1 1</param>
        /// <param name="max">分数最大值 +inf (10 10</param>
        /// <returns></returns>
        public static long ZRemRangeByScore(string key, string min, string max)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRemRangeByScore(key, min, max);
        }

        /// <summary>
        /// 返回有序集中指定区间内的成员，通过索引，分数从高到底
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="start">开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop">结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <returns></returns>
        public static string[] ZRevRange(string key, long start, long stop)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRevRange(key, start, stop);
        }

        /// <summary>
        /// 返回有序集中指定区间内的成员，通过索引，分数从高到底
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="start">开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop">结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <returns></returns>
        public static T[] ZRevRange<T>(string key, long start, long stop)
        {
            var redisClient = GetRedisClient(key);

            return redisClient.ZRevRange<T>(key, start, stop);
        }

        /// <summary>
        /// 返回有序集中指定区间内的成员和分数，通过索引，分数从高到底
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="start">开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop">结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <returns></returns>
        public static (string member, decimal score)[] ZRevRangeWithScores(string key, long start, long stop)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRevRangeWithScores(key, start, stop);
        }

        /// <summary>
        /// 返回有序集中指定区间内的成员和分数，通过索引，分数从高到底
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="start">开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop">结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <returns></returns>
        public static (T member, decimal score)[] ZRevRangeWithScores<T>(string key, long start, long stop)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRevRangeWithScores<T>(key, start, stop);
        }

        /// <summary>
        /// 返回有序集中指定分数区间内的成员，分数从高到低排序
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="max">分数最大值 decimal.MaxValue</param>
        /// <param name="min">分数最小值 decimal.MinValue</param>
        /// <param name="limit">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public static string[] ZRevRangeByScore(string key, decimal max, decimal min, long? limit = null, long? offset = 0)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRevRangeByScore(key, max, min, limit, offset);
        }

        /// <summary>
        /// 返回有序集中指定分数区间内的成员，分数从高到低排序
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="max">分数最大值 decimal.MaxValue</param>
        /// <param name="min">分数最小值 decimal.MinValue</param>
        /// <param name="limit">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public static T[] ZRevRangeByScore<T>(string key, decimal max, decimal min, long? limit = null, long offset = 0)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRevRangeByScore<T>(key, max, min, limit, offset);
        }

        /// <summary>
        /// 返回有序集中指定分数区间内的成员，分数从高到低排序
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="max">分数最大值 +inf (10 10</param>
        /// <param name="min">分数最小值 -inf (1 1</param>
        /// <param name="limit">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public static string[] ZRevRangeByScore(string key, string max, string min, long? limit = null, long? offset = 0)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRevRangeByScore(key, max, min, limit, offset);
        }

        /// <summary>
        /// 返回有序集中指定分数区间内的成员，分数从高到低排序
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="max">分数最大值 +inf (10 10</param>
        /// <param name="min">分数最小值 -inf (1 1</param>
        /// <param name="limit">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public static T[] ZRevRangeByScore<T>(string key, string max, string min, long? limit = null, long offset = 0)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRevRangeByScore<T>(key, max, min, limit, offset);
        }

        /// <summary>
        /// 返回有序集中指定分数区间内的成员和分数，分数从高到低排序
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="max">分数最大值 decimal.MaxValue</param>
        /// <param name="min">分数最小值 decimal.MinValue</param>
        /// <param name="limit">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public static (string member, decimal score)[] ZRevRangeByScoreWithScores(string key, decimal max, decimal min, long? limit = null, long offset = 0)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRevRangeByScoreWithScores(key, max, min, limit, offset);
        }

        /// <summary>
        /// 返回有序集中指定分数区间内的成员和分数，分数从高到低排序
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="max">分数最大值 decimal.MaxValue</param>
        /// <param name="min">分数最小值 decimal.MinValue</param>
        /// <param name="limit">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public static (T member, decimal score)[] ZRevRangeByScoreWithScores<T>(string key, decimal max, decimal min, long? limit = null, long offset = 0)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRevRangeByScoreWithScores<T>(key, max, min, limit, offset);
        }

        /// <summary>
        /// 返回有序集中指定分数区间内的成员和分数，分数从高到低排序
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="max">分数最大值 +inf (10 10</param>
        /// <param name="min">分数最小值 -inf (1 1</param>
        /// <param name="limit">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public static (string member, decimal score)[] ZRevRangeByScoreWithScores(string key, string max, string min, long? limit = null, long offset = 0)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRevRangeByScoreWithScores(key, max, min, limit, offset);
        }

        /// <summary>
        /// 返回有序集中指定分数区间内的成员和分数，分数从高到低排序
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="max">分数最大值 +inf (10 10</param>
        /// <param name="min">分数最小值 -inf (1 1</param>
        /// <param name="limit">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public static (T member, decimal score)[] ZRevRangeByScoreWithScores<T>(string key, string max, string min, long? limit = null, long offset = 0)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRevRangeByScoreWithScores<T>(key, max, min, limit, offset);
        }

        /// <summary>
        /// 返回有序集合中指定成员的排名，有序集成员按分数值递减(从大到小)排序
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="member">成员</param>
        /// <returns></returns>
        public static long? ZRevRank(string key, object member)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRevRank(key, member);
        }

        /// <summary>
        /// 返回有序集中，成员的分数值
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="member">成员</param>
        /// <returns></returns>
        public static decimal? ZScore(string key, object member)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZScore(key, member);
        }

        /// <summary>
        /// 迭代有序集合中的元素
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="cursor">位置</param>
        /// <param name="pattern">模式</param>
        /// <param name="count">数量</param>
        /// <returns></returns>
        public static RedisScan<(string member, decimal score)> ZScan(string key, int cursor, string pattern = null, int? count = null)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZScan(key, cursor, pattern, count);
        }

        /// <summary>
        /// 迭代有序集合中的元素
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="cursor">位置</param>
        /// <param name="pattern">模式</param>
        /// <param name="count">数量</param>
        /// <returns></returns>
        public static RedisScan<(T member, decimal score)> ZScan<T>(string key, int cursor, string pattern = null, int? count = null)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZScan<T>(key, cursor, pattern, count);
        }

        /// <summary>
        /// 当有序集合的所有成员都具有相同的分值时，有序集合的元素会根据成员的字典序来进行排序，这个命令可以返回给定的有序集合键 key 中，值介于 min 和 max 之间的成员。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="min">'(' 表示包含在范围，'[' 表示不包含在范围，'+' 正无穷大，'-' 负无限。 ZRANGEBYLEX zset - + ，命令将返回有序集合中的所有元素</param>
        /// <param name="max">'(' 表示包含在范围，'[' 表示不包含在范围，'+' 正无穷大，'-' 负无限。 ZRANGEBYLEX zset - + ，命令将返回有序集合中的所有元素</param>
        /// <param name="limit">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public static string[] ZRangeByLex(string key, string min, string max, long? limit = null, long offset = 0)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRangeByLex(key, min, max, limit, offset);
        }

        /// <summary>
        /// 当有序集合的所有成员都具有相同的分值时，有序集合的元素会根据成员的字典序来进行排序，这个命令可以返回给定的有序集合键 key 中，值介于 min 和 max 之间的成员。
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="min">'(' 表示包含在范围，'[' 表示不包含在范围，'+' 正无穷大，'-' 负无限。 ZRANGEBYLEX zset - + ，命令将返回有序集合中的所有元素</param>
        /// <param name="max">'(' 表示包含在范围，'[' 表示不包含在范围，'+' 正无穷大，'-' 负无限。 ZRANGEBYLEX zset - + ，命令将返回有序集合中的所有元素</param>
        /// <param name="limit">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <returns></returns>
        public static T[] ZRangeByLex<T>(string key, string min, string max, long? limit = null, long offset = 0)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRangeByLex<T>(key, min, max, limit, offset);
        }

        /// <summary>
        /// 当有序集合的所有成员都具有相同的分值时，有序集合的元素会根据成员的字典序来进行排序，这个命令可以返回给定的有序集合键 key 中，值介于 min 和 max 之间的成员。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="min">'(' 表示包含在范围，'[' 表示不包含在范围，'+' 正无穷大，'-' 负无限。 ZRANGEBYLEX zset - + ，命令将返回有序集合中的所有元素</param>
        /// <param name="max">'(' 表示包含在范围，'[' 表示不包含在范围，'+' 正无穷大，'-' 负无限。 ZRANGEBYLEX zset - + ，命令将返回有序集合中的所有元素</param>
        /// <returns></returns>
        public static long ZRemRangeByLex(string key, string min, string max)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZRemRangeByLex(key, min, max);
        }

        /// <summary>
        /// 当有序集合的所有成员都具有相同的分值时，有序集合的元素会根据成员的字典序来进行排序，这个命令可以返回给定的有序集合键 key 中，值介于 min 和 max 之间的成员。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="min">'(' 表示包含在范围，'[' 表示不包含在范围，'+' 正无穷大，'-' 负无限。 ZRANGEBYLEX zset - + ，命令将返回有序集合中的所有元素</param>
        /// <param name="max">'(' 表示包含在范围，'[' 表示不包含在范围，'+' 正无穷大，'-' 负无限。 ZRANGEBYLEX zset - + ，命令将返回有序集合中的所有元素</param>
        /// <returns></returns>
        public static long ZLexCount(string key, string min, string max)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.ZLexCount(key, min, max);
        }

        #endregion

        #region Geo redis-server 3.2

        /// <summary>
        /// 将指定的地理空间位置（纬度、经度、成员）添加到指定的key中。这些数据将会存储到sorted set这样的目的是为了方便使用GEORADIUS或者GEORADIUSBYMEMBER命令对数据进行半径查询等操作。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="longitude">经度</param>
        /// <param name="latitude">纬度</param>
        /// <param name="member">成员</param>
        /// <returns>是否成功</returns>
        public static bool GeoAdd(string key, decimal longitude, decimal latitude, object member)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.GeoAdd(key, longitude, latitude, member);
        }
        /// <summary>
        /// 将指定的地理空间位置（纬度、经度、成员）添加到指定的key中。这些数据将会存储到sorted set这样的目的是为了方便使用GEORADIUS或者GEORADIUSBYMEMBER命令对数据进行半径查询等操作。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="values">批量添加的值</param>
        /// <returns>添加到sorted set元素的数目，但不包括已更新score的元素。</returns>
        public static long GeoAdd(string key, params (decimal longitude, decimal latitude, object member)[] values)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.GeoAdd(key, values);
        }
        /// <summary>
        /// 将指定的地理空间位置（纬度、经度、成员）添加到指定的key中。这些数据将会存储到sorted set这样的目的是为了方便使用GEORADIUS或者GEORADIUSBYMEMBER命令对数据进行半径查询等操作。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="values">批量添加的值</param>
        /// <returns>添加到sorted set元素的数目，但不包括已更新score的元素。</returns>
        public static long GeoAdd(string key, params GeoAddDto[] values)
        {
            var redisClient = GetRedisClient(key);
            List<(decimal longitude, decimal latitude, object member)> list = new List<(decimal longitude, decimal latitude, object member)>();
            foreach (var item in values)
            {
                list.Add((item.Longitude, item.Latitude, item.Member));
            }
            return redisClient.GeoAdd(key, list.ToArray());
        }

        /// <summary>
        /// 返回两个给定位置之间的距离。如果两个位置之间的其中一个不存在， 那么命令返回空值。GEODIST 命令在计算距离时会假设地球为完美的球形， 在极限情况下， 这一假设最大会造成 0.5% 的误差。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="member1">成员1</param>
        /// <param name="member2">成员2</param>
        /// <param name="unit">m 表示单位为米；km 表示单位为千米；mi 表示单位为英里；ft 表示单位为英尺；</param>
        /// <returns>计算出的距离会以双精度浮点数的形式被返回。 如果给定的位置元素不存在， 那么命令返回空值。</returns>
        public static decimal? GeoDist(string key, object member1, object member2, GeoUnit unit = GeoUnit.m)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.GeoDist(key, member1, member2, unit);
        }

        /// <summary>
        /// 返回一个或多个位置元素的 Geohash 表示。通常使用表示位置的元素使用不同的技术，使用Geohash位置52点整数编码。由于编码和解码过程中所使用的初始最小和最大坐标不同，编码的编码也不同于标准。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="members">多个查询的成员</param>
        /// <returns>一个数组， 数组的每个项都是一个 geohash 。 命令返回的 geohash 的位置与用户给定的位置元素的位置一一对应。</returns>
        public static string[] GeoHash(string key, object[] members)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.GeoHash(key, members);
        }

        /// <summary>
        /// 从key里返回所有给定位置元素的位置（经度和纬度）。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="members">多个查询的成员</param>
        /// <returns>GEOPOS 命令返回一个数组， 数组中的每个项都由两个元素组成： 第一个元素为给定位置元素的经度， 而第二个元素则为给定位置元素的纬度。当给定的位置元素不存在时， 对应的数组项为空值。</returns>
        public static (decimal longitude, decimal latitude)?[] GeoPos(string key, object[] members)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.GeoPos(key, members);
        }

        /// <summary>
        /// 以给定的经纬度为中心， 返回键包含的位置元素当中， 与中心的距离不超过给定最大距离的所有位置元素。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="longitude">经度</param>
        /// <param name="latitude">纬度</param>
        /// <param name="radius">距离</param>
        /// <param name="unit">m 表示单位为米；km 表示单位为千米；mi 表示单位为英里；ft 表示单位为英尺；</param>
        /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素， 但是因为命令在内部可能会需要对所有被匹配的元素进行处理， 所以在对一个非常大的区域进行搜索时， 即使只使用 COUNT 选项去获取少量元素， 命令的执行速度也可能会非常慢。 但是从另一方面来说， 使用 COUNT 选项去减少需要返回的元素数量， 对于减少带宽来说仍然是非常有用的。</param>
        /// <param name="sorting">排序</param>
        /// <returns></returns>
        public static string[] GeoRadius(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.GeoRadius(key, longitude, latitude, radius, unit, count, sorting);
        }

        /// <summary>
        /// 以给定的经纬度为中心， 返回键包含的位置元素当中， 与中心的距离不超过给定最大距离的所有位置元素。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="longitude">经度</param>
        /// <param name="latitude">纬度</param>
        /// <param name="radius">距离</param>
        /// <param name="unit">m 表示单位为米；km 表示单位为千米；mi 表示单位为英里；ft 表示单位为英尺；</param>
        /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素， 但是因为命令在内部可能会需要对所有被匹配的元素进行处理， 所以在对一个非常大的区域进行搜索时， 即使只使用 COUNT 选项去获取少量元素， 命令的执行速度也可能会非常慢。 但是从另一方面来说， 使用 COUNT 选项去减少需要返回的元素数量， 对于减少带宽来说仍然是非常有用的。</param>
        /// <param name="sorting">排序</param>
        /// <returns></returns>
        public static T[] GeoRadius<T>(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.GeoRadius<T>(key, longitude, latitude, radius, unit, count, sorting);
        }

        /// <summary>
        /// 以给定的经纬度为中心， 返回键包含的位置元素当中， 与中心的距离不超过给定最大距离的所有位置元素（包含距离）。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="longitude">经度</param>
        /// <param name="latitude">纬度</param>
        /// <param name="radius">距离</param>
        /// <param name="unit">m 表示单位为米；km 表示单位为千米；mi 表示单位为英里；ft 表示单位为英尺；</param>
        /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素， 但是因为命令在内部可能会需要对所有被匹配的元素进行处理， 所以在对一个非常大的区域进行搜索时， 即使只使用 COUNT 选项去获取少量元素， 命令的执行速度也可能会非常慢。 但是从另一方面来说， 使用 COUNT 选项去减少需要返回的元素数量， 对于减少带宽来说仍然是非常有用的。</param>
        /// <param name="sorting">排序</param>
        /// <returns></returns>
        public static (string member, decimal dist)[] GeoRadiusWithDist(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.GeoRadiusWithDist(key, longitude, latitude, radius, unit, count, sorting);
        }
        /// <summary>
        /// 以给定的经纬度为中心， 返回键包含的位置元素当中， 与中心的距离不超过给定最大距离的所有位置元素（包含距离）。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="longitude">经度</param>
        /// <param name="latitude">纬度</param>
        /// <param name="radius">距离</param>
        /// <param name="unit">m 表示单位为米；km 表示单位为千米；mi 表示单位为英里；ft 表示单位为英尺；</param>
        /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素， 但是因为命令在内部可能会需要对所有被匹配的元素进行处理， 所以在对一个非常大的区域进行搜索时， 即使只使用 COUNT 选项去获取少量元素， 命令的执行速度也可能会非常慢。 但是从另一方面来说， 使用 COUNT 选项去减少需要返回的元素数量， 对于减少带宽来说仍然是非常有用的。</param>
        /// <param name="sorting">排序</param>
        /// <returns></returns>
        public static (T member, decimal dist)[] GeoRadiusWithDist<T>(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.GeoRadiusWithDist<T>(key, longitude, latitude, radius, unit, count, sorting);
        }

        /// <summary>
        /// 以给定的经纬度为中心， 返回键包含的位置元素当中， 与中心的距离不超过给定最大距离的所有位置元素（包含距离、经度、纬度）。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="longitude">经度</param>
        /// <param name="latitude">纬度</param>
        /// <param name="radius">距离</param>
        /// <param name="unit">m 表示单位为米；km 表示单位为千米；mi 表示单位为英里；ft 表示单位为英尺；</param>
        /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素， 但是因为命令在内部可能会需要对所有被匹配的元素进行处理， 所以在对一个非常大的区域进行搜索时， 即使只使用 COUNT 选项去获取少量元素， 命令的执行速度也可能会非常慢。 但是从另一方面来说， 使用 COUNT 选项去减少需要返回的元素数量， 对于减少带宽来说仍然是非常有用的。</param>
        /// <param name="sorting">排序</param>
        /// <returns></returns>
        public static (string member, decimal dist, decimal longitude, decimal latitude)[] GeoRadiusWithDistAndCoord(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.GeoRadiusWithDistAndCoord(key, longitude, latitude, radius, unit, count, sorting);
        }

        /// <summary>
        /// 以给定的经纬度为中心， 返回键包含的位置元素当中， 与中心的距离不超过给定最大距离的所有位置元素（包含距离、经度、纬度）。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="longitude">经度</param>
        /// <param name="latitude">纬度</param>
        /// <param name="radius">距离</param>
        /// <param name="unit">m 表示单位为米；km 表示单位为千米；mi 表示单位为英里；ft 表示单位为英尺；</param>
        /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素， 但是因为命令在内部可能会需要对所有被匹配的元素进行处理， 所以在对一个非常大的区域进行搜索时， 即使只使用 COUNT 选项去获取少量元素， 命令的执行速度也可能会非常慢。 但是从另一方面来说， 使用 COUNT 选项去减少需要返回的元素数量， 对于减少带宽来说仍然是非常有用的。</param>
        /// <param name="sorting">排序</param>
        /// <returns></returns>
        public static (T member, decimal dist, decimal longitude, decimal latitude)[] GeoRadiusWithDistAndCoord<T>(string key, decimal longitude, decimal latitude, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.GeoRadiusWithDistAndCoord<T>(key, longitude, latitude, radius, unit, count, sorting);
        }

        /// <summary>
        /// 以给定的成员为中心， 返回键包含的位置元素当中， 与中心的距离不超过给定最大距离的所有位置元素。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="member">成员</param>
        /// <param name="radius">距离</param>
        /// <param name="unit">m 表示单位为米；km 表示单位为千米；mi 表示单位为英里；ft 表示单位为英尺；</param>
        /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素， 但是因为命令在内部可能会需要对所有被匹配的元素进行处理， 所以在对一个非常大的区域进行搜索时， 即使只使用 COUNT 选项去获取少量元素， 命令的执行速度也可能会非常慢。 但是从另一方面来说， 使用 COUNT 选项去减少需要返回的元素数量， 对于减少带宽来说仍然是非常有用的。</param>
        /// <param name="sorting">排序</param>
        /// <returns></returns>
        public static string[] GeoRadiusByMember(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.GeoRadiusByMember(key, member, radius, unit, count, sorting);
        }
        /// <summary>
        /// 以给定的成员为中心， 返回键包含的位置元素当中， 与中心的距离不超过给定最大距离的所有位置元素。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="member">成员</param>
        /// <param name="radius">距离</param>
        /// <param name="unit">m 表示单位为米；km 表示单位为千米；mi 表示单位为英里；ft 表示单位为英尺；</param>
        /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素， 但是因为命令在内部可能会需要对所有被匹配的元素进行处理， 所以在对一个非常大的区域进行搜索时， 即使只使用 COUNT 选项去获取少量元素， 命令的执行速度也可能会非常慢。 但是从另一方面来说， 使用 COUNT 选项去减少需要返回的元素数量， 对于减少带宽来说仍然是非常有用的。</param>
        /// <param name="sorting">排序</param>
        /// <returns></returns>
        public static T[] GeoRadiusByMember<T>(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.GeoRadiusByMember<T>(key, member, radius, unit, count, sorting);
        }

        /// <summary>
        /// 以给定的成员为中心， 返回键包含的位置元素当中， 与中心的距离不超过给定最大距离的所有位置元素（包含距离）。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="member">成员</param>
        /// <param name="radius">距离</param>
        /// <param name="unit">m 表示单位为米；km 表示单位为千米；mi 表示单位为英里；ft 表示单位为英尺；</param>
        /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素， 但是因为命令在内部可能会需要对所有被匹配的元素进行处理， 所以在对一个非常大的区域进行搜索时， 即使只使用 COUNT 选项去获取少量元素， 命令的执行速度也可能会非常慢。 但是从另一方面来说， 使用 COUNT 选项去减少需要返回的元素数量， 对于减少带宽来说仍然是非常有用的。</param>
        /// <param name="sorting">排序</param>
        /// <returns></returns>
        public static (string member, decimal dist)[] GeoRadiusByMemberWithDist(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.GeoRadiusByMemberWithDist(key, member, radius, unit, count, sorting);
        }

        /// <summary>
        /// 以给定的成员为中心， 返回键包含的位置元素当中， 与中心的距离不超过给定最大距离的所有位置元素（包含距离）。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="member">成员</param>
        /// <param name="radius">距离</param>
        /// <param name="unit">m 表示单位为米；km 表示单位为千米；mi 表示单位为英里；ft 表示单位为英尺；</param>
        /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素， 但是因为命令在内部可能会需要对所有被匹配的元素进行处理， 所以在对一个非常大的区域进行搜索时， 即使只使用 COUNT 选项去获取少量元素， 命令的执行速度也可能会非常慢。 但是从另一方面来说， 使用 COUNT 选项去减少需要返回的元素数量， 对于减少带宽来说仍然是非常有用的。</param>
        /// <param name="sorting">排序</param>
        /// <returns></returns>
        public static (T member, decimal dist)[] GeoRadiusByMemberWithDist<T>(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.GeoRadiusByMemberWithDist<T>(key, member, radius, unit, count, sorting);
        }
        /// <summary>
        /// 以给定的成员为中心， 返回键包含的位置元素当中， 与中心的距离不超过给定最大距离的所有位置元素（包含距离、经度、纬度）。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="member">成员</param>
        /// <param name="radius">距离</param>
        /// <param name="unit">m 表示单位为米；km 表示单位为千米；mi 表示单位为英里；ft 表示单位为英尺；</param>
        /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素， 但是因为命令在内部可能会需要对所有被匹配的元素进行处理， 所以在对一个非常大的区域进行搜索时， 即使只使用 COUNT 选项去获取少量元素， 命令的执行速度也可能会非常慢。 但是从另一方面来说， 使用 COUNT 选项去减少需要返回的元素数量， 对于减少带宽来说仍然是非常有用的。</param>
        /// <param name="sorting">排序</param>
        /// <returns></returns>
        public static (string member, decimal dist, decimal longitude, decimal latitude)[] GeoRadiusByMemberWithDistAndCoord(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.GeoRadiusByMemberWithDistAndCoord(key, member, radius, unit, count, sorting);
        }

        /// <summary>
        /// 以给定的成员为中心， 返回键包含的位置元素当中， 与中心的距离不超过给定最大距离的所有位置元素（包含距离、经度、纬度）。
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="member">成员</param>
        /// <param name="radius">距离</param>
        /// <param name="unit">m 表示单位为米；km 表示单位为千米；mi 表示单位为英里；ft 表示单位为英尺；</param>
        /// <param name="count">虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素， 但是因为命令在内部可能会需要对所有被匹配的元素进行处理， 所以在对一个非常大的区域进行搜索时， 即使只使用 COUNT 选项去获取少量元素， 命令的执行速度也可能会非常慢。 但是从另一方面来说， 使用 COUNT 选项去减少需要返回的元素数量， 对于减少带宽来说仍然是非常有用的。</param>
        /// <param name="sorting">排序</param>
        /// <returns></returns>
        public static (T member, decimal dist, decimal longitude, decimal latitude)[] GeoRadiusByMemberWithDistAndCoord<T>(string key, object member, decimal radius, GeoUnit unit = GeoUnit.m, long? count = null, GeoOrderBy? sorting = null)
        {
            var redisClient = GetRedisClient(key);
            return redisClient.GeoRadiusByMemberWithDistAndCoord<T>(key, member, radius, unit, count, sorting);
        }

        #endregion

        ///// <summary>
        ///// 开启分布式锁，若超时返回null
        ///// </summary>
        ///// <param name="name">锁名称</param>
        ///// <param name="timeoutSeconds">超时（秒）</param>
        ///// <returns></returns>
        //public static CSRedisClientLock Lock(string name, int timeoutSeconds)
        //{
        //    var redisClient = GetRedisClientFirst();
        //    return redisClient.Lock(name, timeoutSeconds);
        //}


        #region 指定CSRedisClient

        #region Hash
        /// <summary>
        /// 同时将多个 field-value (域-值)对设置到哈希表 key 中
        /// </summary>
        /// <param name="redisClient">Redis客户端</param>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="fieldValues">一个或多个 field value 值</param>
        /// <returns></returns>
        public static bool HMSet(CSRedisClient redisClient, string key, params HashAddDto[] fieldValues)
        {
            List<object> list = new List<object>();
            foreach (var item in fieldValues)
            {
                list.Add(item.Field);
                list.Add(item.Value);
            }
            return redisClient.HMSet(key, list.ToArray());
        }

        #endregion

        #region Sorted Set
        /// <summary>
        /// 向有序集合添加一个或多个成员，或者更新已存在成员的分数
        /// </summary>
        /// <param name="redisClient">Redis客户端</param>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="scoreMembers">一个或多个成员分数</param>
        /// <returns></returns>
        public static long ZAdd(CSRedisClient redisClient, string key, params SortedSetAddDto[] scoreMembers)
        {
            List<(decimal, object)> list = new List<(decimal, object)>();
            foreach (var item in scoreMembers)
            {
                list.Add((item.Score, item.Member));
            }
            return redisClient.ZAdd(key, list.ToArray());
        }
        #endregion

        #region Geo redis
        /// <summary>
        /// 将指定的地理空间位置（纬度、经度、成员）添加到指定的key中。这些数据将会存储到sorted set这样的目的是为了方便使用GEORADIUS或者GEORADIUSBYMEMBER命令对数据进行半径查询等操作。
        /// </summary>
        /// <param name="redisClient">Redis客户端</param>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="values">批量添加的值</param>
        /// <returns>添加到sorted set元素的数目，但不包括已更新score的元素。</returns>
        public static long GeoAdd(CSRedisClient redisClient, string key, params GeoAddDto[] values)
        {
            List<(decimal longitude, decimal latitude, object member)> list = new List<(decimal longitude, decimal latitude, object member)>();
            foreach (var item in values)
            {
                list.Add((item.Longitude, item.Latitude, item.Member));
            }
            return redisClient.GeoAdd(key, list.ToArray());
        }
        #endregion

        #region 获取前缀
        /// <summary>
        /// 获取前缀
        /// </summary>
        /// <param name="redisClient">Redis客户端</param>
        /// <returns>前缀</returns>
        public static string GetPrefix(CSRedisClient redisClient)
        {
            string prefix = string.Empty;
            if (redisClient.Nodes != null && redisClient.Nodes.Count > 0)
            {
                prefix = redisClient.Nodes.First().Value.Prefix;
            }
            return prefix;
        }
        #endregion

        #region 查询keys
        /// <summary>
        /// 查询keys，会加上前缀
        /// </summary>
        /// <param name="redisClient">Redis客户端</param>
        /// <param name="pattern">匹配</param>
        /// <returns>key数组</returns>
        public static string[] Keys(CSRedisClient redisClient, string pattern)
        {
            string prefix = GetPrefix(redisClient);
            pattern = string.Concat(prefix, pattern);
            var keys = redisClient.Keys(pattern);
            return RemovePrefix(prefix, keys);
        }
        #endregion

        #endregion

        #region 使用分布式锁调用业务逻辑

        /// <summary>
        /// 使用分布式锁调用业务逻辑
        /// </summary>
        /// <param name="lockKey">锁的Key名称</param>
        /// <param name="action">Action业务</param>
        /// <param name="millisecondsTimeout">最多锁定毫秒数</param>
        /// <param name="millisecondsDelay">每次等待毫秒数</param>
        public static void Lock(string lockKey, Action action, int millisecondsTimeout = 10000, int millisecondsDelay = 500)
        {
            var redisClient = GetRedisClient(lockKey);
            Lock(redisClient, lockKey, action, millisecondsTimeout, millisecondsDelay);
        }

        /// <summary>
        /// 使用分布式锁调用业务逻辑
        /// </summary>
        /// <param name="redisClient">redis客户端</param>
        /// <param name="lockKey">锁的Key名称</param>
        /// <param name="action">Action业务</param>
        /// <param name="millisecondsTimeout">最多锁定毫秒数</param>
        /// <param name="millisecondsDelay">每次等待毫秒数</param>
        public static void Lock(CSRedisClient redisClient, string lockKey, Action action, int millisecondsTimeout = 10000, int millisecondsDelay = 500)
        {
            int index = 0;
            while (true)
            {
                //加入分布式锁，防止并发出现异常
                if (redisClient.SetNx(lockKey, "1"))
                {
                    //设定锁的过期时间
                    redisClient.Expire(lockKey, TimeSpan.FromMilliseconds(millisecondsTimeout));
                    try
                    {
                        action();
                        break;
                    }
                    catch (Exception e)
                    {
                        throw e;
                    }
                    finally
                    {
                        //删除锁key
                        redisClient.Del(lockKey);
                    }
                }
                else
                {
                    //如果不是第一次循环，且锁的过期时间为 -1，则表示异常，删除锁
                    if (index > 0 && (redisClient.Ttl(lockKey)) == -1)
                    {
                        //删除锁key
                        redisClient.Del(lockKey);
                    }
                    else
                    {
                        Thread.Sleep(millisecondsDelay);
                    }
                    index++;
                }

            }
        }

        #endregion

        #region 委托方法调用

        #region String
        #region String
        /// <summary>
        /// string 委托获取存值
        /// </summary>
        /// <param name="redisClient">客户端</param>
        /// <param name="key">key</param>
        /// <param name="getValue">委托</param>
        /// <param name="resetExpire">重置过期时间</param>
        /// <param name="expireFunc">设置过期时间方法</param>
        /// <returns></returns>
        private static string GetValue(CSRedisClient redisClient, string key, Func<string> getValue, bool resetExpire, Func<bool> expireFunc)
        {
            if (redisClient.Exists(key))
            {
                var value = redisClient.Get(key);
                if (resetExpire)
                {
                    expireFunc();
                }
                return value;
            }
            else
            {
                var value = getValue();
                redisClient.Set(key, value);
                expireFunc();
                return value;
            }
        }

        /// <summary>
        /// 获取指定Key的值
        /// 如何key不存在，则从委托中获取
        /// </summary>
        /// <param name="redisClient">客户端</param>
        /// <param name="key">key</param>
        /// <param name="getValue">委托</param>
        /// <param name="resetExpire">重置过期时间</param>
        /// <returns></returns>
        public static string Get(CSRedisClient redisClient, string key, Func<string> getValue, bool resetExpire = false)
        {
            return GetValue(redisClient, key, getValue, resetExpire, () =>
            {
                TimeSpan? expire = GetExpire(key);
                if (expire.HasValue)
                {
                    return redisClient.Expire(key, expire.Value);
                }
                return true;
            });
        }
        /// <summary>
        /// 获取指定Key的值
        /// 如何key不存在，则从委托中获取
        /// </summary>
        /// <param name="redisClient">客户端</param>
        /// <param name="key">key</param>
        /// <param name="getValue">委托</param>
        /// <param name="seconds">过期秒数</param>
        /// <param name="resetExpire">重置过期时间</param>
        /// <returns></returns>
        public static string Get(CSRedisClient redisClient, string key, Func<string> getValue, int seconds, bool resetExpire = false)
        {
            return GetValue(redisClient, key, getValue, resetExpire, () =>
            {
                return redisClient.Expire(key, seconds);
            });
        }
        /// <summary>
        /// 获取指定Key的值
        /// 如何key不存在，则从委托中获取
        /// </summary>
        /// <param name="redisClient">客户端</param>
        /// <param name="key">key</param>
        /// <param name="getValue">委托</param>
        /// <param name="expire">过期时间</param>
        /// <param name="resetExpire">重置过期时间</param>
        /// <returns></returns>
        public static string Get(CSRedisClient redisClient, string key, Func<string> getValue, TimeSpan expire, bool resetExpire = false)
        {
            return GetValue(redisClient, key, getValue, resetExpire, () =>
            {
                return redisClient.Expire(key, expire);
            });
        }

        /// <summary>
        /// 获取指定Key的值
        /// 如何key不存在，则从委托中获取
        /// </summary>
        /// <param name="redisClient">客户端</param>
        /// <param name="key">key</param>
        /// <param name="getValue">委托</param>
        /// <param name="expire">指定的过期时间</param>
        /// <param name="resetExpire">重置过期时间</param>
        /// <returns></returns>
        public static string Get(CSRedisClient redisClient, string key, Func<string> getValue, DateTime expire, bool resetExpire = false)
        {
            return GetValue(redisClient, key, getValue, resetExpire, () =>
            {
                return redisClient.ExpireAt(key, expire);
            });
        }
        /// <summary>
        /// 获取指定Key的值
        /// 如何key不存在，则从委托中获取
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="getValue">委托</param>
        /// <param name="resetExpire">重置过期时间</param>
        /// <returns></returns>
        public static string Get(string key, Func<string> getValue, bool resetExpire = false)
        {
            var redisClient = GetRedisClient(key);
            return Get(redisClient, key, getValue, resetExpire);
        }
        /// <summary>
        /// 获取指定Key的值
        /// 如何key不存在，则从委托中获取
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="getValue">委托</param>
        /// <param name="seconds">过期秒数</param>
        /// <param name="resetExpire">重置过期时间</param>
        /// <returns></returns>
        public static string Get(string key, Func<string> getValue, int seconds, bool resetExpire = false)
        {
            var redisClient = GetRedisClient(key);
            return Get(redisClient, key, getValue, seconds, resetExpire);
        }
        /// <summary>
        /// 获取指定Key的值
        /// 如何key不存在，则从委托中获取
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="getValue">委托</param>
        /// <param name="expire">过期时间</param>
        /// <param name="resetExpire">重置过期时间</param>
        /// <returns></returns>
        public static string Get(string key, Func<string> getValue, TimeSpan expire, bool resetExpire = false)
        {
            var redisClient = GetRedisClient(key);
            return Get(redisClient, key, getValue, expire, resetExpire);
        }
        /// <summary>
        /// 获取指定Key的值
        /// 如何key不存在，则从委托中获取
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="getValue">委托</param>
        /// <param name="expire">指定的过期时间</param>
        /// <param name="resetExpire">重置过期时间</param>
        /// <returns></returns>
        public static string Get(string key, Func<string> getValue, DateTime expire, bool resetExpire = false)
        {
            var redisClient = GetRedisClient(key);
            return Get(redisClient, key, getValue, expire, resetExpire);
        }

        #endregion

        #region 泛型
        /// <summary>
        /// string 委托获取存值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="redisClient">客户端</param>
        /// <param name="key">key</param>
        /// <param name="getValue">委托</param>
        /// <param name="resetExpire">重置过期时间</param>
        /// <param name="expireFunc">设置过期时间方法</param>
        /// <returns></returns>
        private static T GetValue<T>(CSRedisClient redisClient, string key, Func<T> getValue, bool resetExpire, Func<bool> expireFunc)
        {
            if (redisClient.Exists(key))
            {
                var value = redisClient.Get<T>(key);
                if (resetExpire)
                {
                    expireFunc();
                }
                return value;
            }
            else
            {
                var value = getValue();
                redisClient.Set(key, value);
                expireFunc();
                return value;
            }
        }
        /// <summary>
        /// 获取指定Key的值
        /// 如何key不存在，则从委托中获取
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="redisClient">客户端</param>
        /// <param name="key">key</param>
        /// <param name="getValue">委托</param>
        /// <param name="resetExpire">重置过期时间</param>
        /// <returns></returns>
        public static T Get<T>(CSRedisClient redisClient, string key, Func<T> getValue, bool resetExpire = false)
        {
            return GetValue(redisClient, key, getValue, resetExpire, () =>
            {
                TimeSpan? expire = GetExpire(key);
                if (expire.HasValue)
                {
                    return redisClient.Expire(key, expire.Value);
                }
                return true;
            });
        }
        /// <summary>
        /// 获取指定Key的值
        /// 如何key不存在，则从委托中获取
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="redisClient">客户端</param>
        /// <param name="key">key</param>
        /// <param name="getValue">委托</param>
        /// <param name="seconds">过期秒数</param>
        /// <param name="resetExpire">重置过期时间</param>
        /// <returns></returns>
        public static T Get<T>(CSRedisClient redisClient, string key, Func<T> getValue, int seconds, bool resetExpire = false)
        {
            return GetValue(redisClient, key, getValue, resetExpire, () =>
            {
                return redisClient.Expire(key, seconds);
            });
        }
        /// <summary>
        /// 获取指定Key的值
        /// 如何key不存在，则从委托中获取
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="redisClient">客户端</param>
        /// <param name="key">key</param>
        /// <param name="getValue">委托</param>
        /// <param name="expire">过期时间</param>
        /// <param name="resetExpire">重置过期时间</param>
        /// <returns></returns>
        public static T Get<T>(CSRedisClient redisClient, string key, Func<T> getValue, TimeSpan expire, bool resetExpire = false)
        {
            return GetValue(redisClient, key, getValue, resetExpire, () =>
            {
                return redisClient.Expire(key, expire);
            });
        }

        /// <summary>
        /// 获取指定Key的值
        /// 如何key不存在，则从委托中获取
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="redisClient">客户端</param>
        /// <param name="key">key</param>
        /// <param name="getValue">委托</param>
        /// <param name="expire">指定的过期时间</param>
        /// <param name="resetExpire">重置过期时间</param>
        /// <returns></returns>
        public static T Get<T>(CSRedisClient redisClient, string key, Func<T> getValue, DateTime expire, bool resetExpire = false)
        {
            return GetValue(redisClient, key, getValue, resetExpire, () =>
            {
                return redisClient.ExpireAt(key, expire);
            });
        }
        /// <summary>
        /// 获取指定Key的值
        /// 如何key不存在，则从委托中获取
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">key</param>
        /// <param name="getValue">委托</param>
        /// <param name="resetExpire">重置过期时间</param>
        /// <returns></returns>
        public static T Get<T>(string key, Func<T> getValue, bool resetExpire = false)
        {
            var redisClient = GetRedisClient(key);
            return Get(redisClient, key, getValue, resetExpire);
        }
        /// <summary>
        /// 获取指定Key的值
        /// 如何key不存在，则从委托中获取
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">key</param>
        /// <param name="getValue">委托</param>
        /// <param name="seconds">过期秒数</param>
        /// <param name="resetExpire">重置过期时间</param>
        /// <returns></returns>
        public static T Get<T>(string key, Func<T> getValue, int seconds, bool resetExpire = false)
        {
            var redisClient = GetRedisClient(key);
            return Get(redisClient, key, getValue, seconds, resetExpire);
        }
        /// <summary>
        /// 获取指定Key的值
        /// 如何key不存在，则从委托中获取
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">key</param>
        /// <param name="getValue">委托</param>
        /// <param name="expire">过期时间</param>
        /// <param name="resetExpire">重置过期时间</param>
        /// <returns></returns>
        public static T Get<T>(string key, Func<T> getValue, TimeSpan expire, bool resetExpire = false)
        {
            var redisClient = GetRedisClient(key);
            return Get(redisClient, key, getValue, expire, resetExpire);
        }
        /// <summary>
        /// 获取指定Key的值
        /// 如何key不存在，则从委托中获取
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">key</param>
        /// <param name="getValue">委托</param>
        /// <param name="expire">指定的过期时间</param>
        /// <param name="resetExpire">重置过期时间</param>
        /// <returns></returns>
        public static T Get<T>(string key, Func<T> getValue, DateTime expire, bool resetExpire = false)
        {
            var redisClient = GetRedisClient(key);
            return Get(redisClient, key, getValue, expire, resetExpire);
        }

        #endregion

        #endregion


        #endregion

        #region 私有方法
        /// <summary>
        /// 去掉前缀
        /// </summary>
        /// <param name="prefix">前缀</param>
        /// <param name="key">完整key</param>
        /// <returns>去掉前缀后的key</returns>
        private static string RemovePrefix(string prefix, string key)
        {
            return key.Substring(prefix.Length);
        }
        /// <summary>
        /// 去掉前缀
        /// </summary>
        /// <param name="prefix">前缀</param>
        /// <param name="keys">完整keys</param>
        /// <returns>去掉前缀后的keys</returns>
        private static string[] RemovePrefix(string prefix, string[] keys)
        {
            for (int i = 0; i < keys.Length; i++)
            {
                keys[i] = RemovePrefix(prefix, keys[i]);
            }
            return keys;
        }
        #endregion

    }
}
